<?php
// +----------------------------------------------------------------------
// | Bwsaas
// +----------------------------------------------------------------------
// | Copyright (c) 2015~2020 http://www.buwangyun.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Gitee ( https://gitee.com/buwangyun/bwsaas )
// +----------------------------------------------------------------------
// | Author: buwangyun <hnlg666@163.com>
// +----------------------------------------------------------------------
// | Date: 2020-9-28 10:55:00
// +----------------------------------------------------------------------

namespace app\manage\model;

use buwang\base\BaseModel;
use buwang\traits\JwtTrait;
use app\manage\model\Member;
use app\common\model\MemberMiniapp;
use buwang\util\Util;
use buwang\util\Sql;
use buwang\exception\MiniappException;

/**  配置组数据
 * Class ConfigGroup
 * @package app\manage\model
 */
class ConfigGroupData extends BaseModel
{
    use JwtTrait;

    /**
     * 数据表主键
     * @var string
     */
    protected $pk = 'id';

    /**
     * 模型名称
     * @var string
     */
    protected $name = 'sys_config_group_data';


    /**前端需要展示的字段数据
     * @param $tab_name
     * @param $type
     */
    public static function getShowData($group_id = null, $ConfigGroupData = null, $member_id = 0, $scopes = 'common', $dir = null)
    {
        //返回数据
        $data = array();

        //查询所有tab
        $ConfigTab = self::getBaseGroupModel($dir, true); //TODO 2021/4/22 如果是应用组合数据从应用中取
        if ($group_id) $ConfigTab = $ConfigTab->where('id|config_name', $group_id);
        if ($scopes) $ConfigTab = $ConfigTab->where('scopes', $scopes);
        if ($dir) $ConfigTab = $ConfigTab->where('dir', $dir);
        $ConfigTab = $ConfigTab->find();
        if (!$ConfigTab) return $data;
        $ConfigTab = $ConfigTab->toArray();

        $ConfigTab['config_list'] = [];
        //查询所有tab下的配置
        $fields = $ConfigTab['fields'];
        $configs = json_decode($fields, true);//json串传数组

        if ($configs) {
            $ConfigGroupDataValue = null;
            //如果存在组合数据则值使用组合数据的值
            if ($ConfigGroupData) {
                //解析得到组合数据的数据
                $vaule = $ConfigGroupData['value'];
                $ConfigGroupDataValue = json_decode(htmlspecialchars_decode($vaule), true);
            }
            //处理多行文本域转移字符
            foreach ($configs as &$config) {
                if ($ConfigGroupDataValue) {
                    if (isset($ConfigGroupDataValue[$config['config_name']])) {
                        $config['value'] = $ConfigGroupDataValue[$config['config_name']]['value'];
                    }
                }

                $config['files'] = [];
                //拼装字段数据
                if ($config['type'] == 'r_textarea' || $config['type'] == 'upload') {
                    $r_textarea = base64_decode($config['value']);
                    $config['value'] = htmlspecialchars_decode(urldecode($r_textarea));
                }

                //处理单选框和多选框和下拉框
                if ($config['type'] == 'radio' || $config['type'] == 'checkbox' || $config['type'] == 'select' || $config['type'] == 'selects') {
                    $parameter = $config['parameter'];
                    $parameter = explode("\n", $parameter);
                    $datas = array();
                    foreach ($parameter as $value) {
                        $value = explode("=>", $value);
                        $datas[] = [
                            'key' => $value[0],
                            'value' => $value[1],
                        ];

                    }
                    $config['parameter'] = $datas;
                }

                //处理文件上传
                if ($config['type'] == 'upload') {
                    switch ($config['upload_type']) {
                        case 1: //单图
                            $config['value'] = $config['value'];
                            if ($config['value']) {
                                $upload_date = json_decode($config['value'], true);//json串传数组
                                if ($upload_date) {
                                    $config['files'] = $upload_date;
                                    $config['value'] = $upload_date['src'];
                                }
                            }
                            break;
                        case 2: //多图
                            $config['value'] = $config['value'];
                            if ($config['value']) {
                                $upload_date = json_decode($config['value'], true);//json串传数组
                                if ($upload_date) {
                                    $config['files'] = $upload_date;
                                    $config['value'] = implode(",", array_column($upload_date, 'src'));
                                }
                            }
                            break;
                        case 3: //文件
                            $config['value'] = $config['value'];
                            if ($config['value']) {
                                $upload_date = json_decode($config['value'], true);//json串传数组
                                if ($upload_date) {
                                    $config['files'] = $upload_date;
                                }
                            }
                            break;

                    }
                }
            }


            $ConfigTab['config_list'] = $configs;

            return $ConfigTab;
        }
        return $data;
    }


    /*
* 设置查询初始化条件
* @param string $alias 表别名
* @param object $model 模型实例化对象
* @return object
* */
    public static function valiWhere($alias = '', $model = null, $dir = '')
    {
        if ($dir) {
            $model = is_null($model) ? self::getAppGroupDataModel($dir) : $model;
            if (!$model) throw new MiniappException("该应用組合數據表缺失，请创建{$dir}的组合数据表");
        } else {
            $model = is_null($model) ? new self() : $model;
        }
        if ($alias) {
            $model = $model->alias($alias);
            $alias .= '.';
        }
        return $model;
    }


    /**添加修改数据
     * @param array $param
     */
    public static function setValues($params = [], $member_id = 0, $scopes = 'common', $trans = false)
    {
        $group_id = $params['group_id'] ?? 0;
        $id = $params['id'] ?? 0;
        $sort = $params['sort'] ?? 0;
        $status = $params['status'] ?? 0;
        $dir = $params['app'] ?? null;
        unset($params['file']);
        unset($params['id']);
        unset($params['group_id']);
        unset($params['sort']);
        unset($params['status']);
        unset($params['app']);
        $configGroup = self::getBaseGroupModel($dir, true)->where('config_name', $group_id);
        if ($dir) $configGroup = $configGroup->where('dir', $dir);
        $ConfigGroup = $configGroup->find();
        if (!$ConfigGroup) $ConfigGroup = self::getBaseGroupModel($dir, true)->find($group_id);
        if (!$ConfigGroup) return self::setError('数据组不存在');
        $fields = json_decode($ConfigGroup['fields'], true);
        if (!$fields) return self::setError('数据组字段配置异常');
        $scopes = $ConfigGroup['scopes'];
        $configs = array();
        foreach ($fields as $field) {
            $configs[$field['config_name']] = $field;
        }
        //需要更新的数据
        $update_data = array();
        //需要给每个租户添加的初始化组合数据
        $init_data = array();
        //验证规则数据
        $rule = array();
        //验证提示数据
        $message = array();
        //待验证数据
        $validate_list = array();
        $type = null;
        //取出所用的数据
        if (!$params) return true;


        //组装提交数据
        foreach ($params as $param_name => $param_value) {

            //查询该参数名的数据
            if (!isset($configs[$param_name])) {
                unset($configs[$param_name]);
                continue;
            }
            $config = $configs[$param_name];
            // var_dump($config);die;
            $type = $config['type'];
            //如果是文本值查看是否有验证规则
            if ($config['type'] == 'text') {
                if (!isset($config['input_type'])) $config['input_type'] = 'text';
                $type = $config['input_type'];
                //测试是否有文本
                if ($config['input_type'] == 'text' || $config['input_type'] == 'number' || $config['input_type'] == 'float') {
                    //如果有规则加上
                    if ($config['rule']) {
                        $rule[$config['config_name'] . '|' . $config['info']] = $config['rule'];
                        $validate_list[$param_name] = $param_value;
                        //查看是否有验证提示
                        if ($config['message']) {
                            $config['message'] = explode('|', $config['message']);
                            foreach ($config['message'] as $value) {
                                $value = explode('=>', $value);
                                if (count($value) != 2) return self::setError('提交数据中，字段【' . $param_name . '】对应的验证提示配置不正确');
                                $message[$value[0]] = $value[1];
                            }
                        }
                    }
                }


                //日期类型转时间戳
                if ($config['input_type'] == 'timestamp') $param_value = strtotime($param_value);
            }
            //如果是多选框得到拼接值
            if ($config['type'] == 'checkbox') {
                //if(!$param_value)return self::setError('提交数据中，字段【'.$param_name.'】复选框值不能为空');
                $param_value = implode(",", $param_value);//数组合并成字符串;
            }
            //如果是富文本和文件上传则base64编码
            if ($config['type'] == 'r_textarea') {
                //先url编码，后base64编码
                $param_value = base64_encode(urlencode($param_value));

            }
            //如果是单选框
            if ($config['type'] == 'radio') {
                // var_dump($param_value);die;
//                if(!$param_value)return self::setError('提交数据中，字段【'.$param_name.'】单选框值不能为空');
            }
            if ($config['type'] == 'select') {

            }
            //如果是上传组件转化json格式
            if ($config['type'] == 'upload') {
                //单图
                if ($config['upload_type'] == '1') {
                    //{"name":"透明.png","size":172692,"type":"image/png","src":"http://www.bwsaas.com/upload/20201103\\4848bd71e499aacb95990527c365d45d.png"}
                    //如果不是json格式的图片则查询上传管理塞进json格式

                    $upload_json = json_decode($param_value, true);//json串传数组
                    if (!$upload_json) {
                        //查询上传信息
                        $upload_file = \app\common\model\SysUploadfile::where('url', $param_value)->find();
                        if ($upload_file) {
                            $param_value = json_encode([
                                'name' => $upload_file['original_name'],
                                'size' => $upload_file['file_size'],
                                'type' => $upload_file['mime_type'],
                                'src' => $upload_file['url'],
                            ]);
                            $param_value = base64_encode(urlencode($param_value));
                        } else {
                            if ($param_value) {
                                $param_value = json_encode([
                                    'name' => basename($param_value),
                                    'size' => 0,
                                    'type' => '',
                                    'src' => $param_value,
                                ]);
                                $param_value = base64_encode(urlencode($param_value));
                            } else {
                                $param_value = null;
                            }
                        }
                    }
                }
                //多图
                if ($config['upload_type'] == '2') {
                    //如果不是json格式的图片则查询上传管理塞进json格式
                    $upload_json = json_decode($param_value, true);//json串传数组
//                    var_dump($config['id']);die;
                    if (!$upload_json) {
                        $imgs = explode(',', $param_value);//字符串分割数组
                        //查询上传信息
                        $upload_files = \app\common\model\SysUploadfile::where('url', 'in', $imgs)->select()->toArray();
                        $data = [];
                        if ($upload_files) {
                            foreach ($upload_files as $upload_file) {
                                $data[] = [
                                    'name' => $upload_file['original_name'],
                                    'size' => $upload_file['file_size'],
                                    'type' => $upload_file['mime_type'],
                                    'src' => $upload_file['url'],
                                ];
                            }
                            $param_value = json_encode($data);//数组转json;
                            $param_value = base64_encode(urlencode($param_value));
                        } else {
                            if ($param_value) {
                                foreach ($imgs as $img) {
                                    $data[] = [
                                        'name' => basename($img),
                                        'size' => 0,
                                        'type' => '',
                                        'src' => $img,
                                    ];
                                }
                                $param_value = json_encode($data);//数组转json;
                                $param_value = base64_encode(urlencode($param_value));
                            } else {
                                $param_value = null;
                            }
                        }
                    }
                }
                if ($config['upload_type'] == '3') {
                    if ($param_value) $param_value = base64_encode(urlencode($param_value));
                }
            }
            $update_data[$param_name] = [
                'type' => $type,
                'value' => $param_value,
            ];
        }
        //待验证的动态验证
        if ($rule) {
            $validate = Validate::rule($rule);
            if ($message) $validate = $validate->message($message);
            if ($validate_list) {
                if (!$validate->check($validate_list)) {
                    return self::setError($validate->getError());
                    //var_dump();die;
                }
            }

        }
        if (!$update_data) return self::setError('提交数据中，无有效数据');
        //是否必填判断
        foreach ($fields as $field) {
            if (!isset($update_data[$field['config_name']])) {
                if (isset($field['must']) && $field['must'] == '1') return self::setError('缺少【' . $field['info'] . '】的值，该字段不能为空');

            } else {
                if (isset($field['must']) && $field['must'] == '1' && (!isset($update_data[$field['config_name']]['value']) || $update_data[$field['config_name']]['value'] === null || $update_data[$field['config_name']]['value'] === "")) return self::setError('缺少【' . $field['info'] . '】的值，该字段不能为空');
            }

        }
        $update_data = str_replace("\\\\", "\\", json_encode($update_data, JSON_UNESCAPED_UNICODE));
        //var_dump($update_data);die;
        //组装提交数据
        $save_data = [
            'group_id' => $ConfigGroup['id'],
            'value' => $update_data,
            'sort' => $sort,
            'status' => $status,
            'scopes' => $scopes,
            'member_id' => $member_id,
            'config_name' => $ConfigGroup['config_name'],
            'dir' => $ConfigGroup['dir'],
            'plugin_name' => $ConfigGroup['plugin_name'] ?? null,
        ];

        if ($id) {
            $groupdata = self::getBaseDataModel($ConfigGroup['dir'], true)->find($id);
            if (!$groupdata) return self::setError('找不到该组合数据');
        } else {
            $save_data['add_time'] = time();
            $groupdata = self::getBaseDataModel($ConfigGroup['dir'], true);
            //如果是新添加的租户初始化数据，则需要给现有的所有租户都加上
            if ($save_data['member_id'] == 0 && $save_data['scopes'] == 'member') {
                //查询所有租户
                $member_ids = Member::where('parent_id', 0)->column('id');
                foreach ($member_ids as $mem_id) {
                    $init_data[] = [
                        'group_id' => $ConfigGroup['id'],
                        'value' => $update_data,
                        'sort' => $sort,
                        'status' => $status,
                        'scopes' => $scopes,
                        'member_id' => $mem_id,
                        'config_name' => $ConfigGroup['config_name'],
                        'dir' => $ConfigGroup['dir'],
                        'plugin_name' => $ConfigGroup['plugin_name'] ?? null,
                        'add_time' => time(),
                    ];
                }

            }


        }

        if ($trans) {
            self::startTrans();
        }
        $res = $res1 = true;
        try {

            $res = $groupdata->save($save_data);
            if ($init_data) {
                $groupdata = self::getBaseDataModel($ConfigGroup['dir'], true);
                $res1 = $groupdata->saveAll($init_data);
            }

            $res = $res && $res1 && true;
            if ($trans) {
                BaseModel::checkTrans($res);
            }
        } catch (\Exception $e) {
            if ($trans) {
                BaseModel::rollback();
            }
            return self::setError($e->getMessage());
        }
        if (!$res1) return self::setError('添加初始化租户数据失败');
        if (!$res) return self::setError('保存失败');

        return $res;


    }

    /** 取数据方法
     * @param string      $where 如果传入的是数据列表或单个数据对象则不需要接收返回结果，直接改变参数本身，如果传入的是id，则需要接收返回结果或将id当做对象
     * @param ConfigGroup $ConfigGroup 数据组对象，可不传，不传的话方法内多查一次数据库
     * @return ConfigGroupData|array|int|mixed|string
     */
    public static function getValueData(&$where, $ConfigGroup = null, $dir = null, $app = null)
    {
        $dataClass = get_class(self::getBaseDataModel($dir, $app));
        try {
            $is_list = false;
            //整形变量
            if (is_int($where)) {
                $data = self::getBaseDataModel($dir, $app)->find($where);
                //字符串整形变量
            } elseif (is_string($where) && is_numeric($where) && strpos($where, ".") === false) {
                $data = self::getBaseDataModel($dir, $app)->find($where);
                //数组
            } elseif (is_array($where)) {
                //判断是数组
                $data = &$where;
                if (!$data) return $data;
                //对象
            } elseif ($where instanceof $dataClass) {
                $data = &$where;
                if (!$data) return $data;
            } else {
                return self::setError('参数1类型不支持，请传递数据数组，数据ID或数据对象');
            }

            if (!$data) return self::setError('找不到数据');

            $datas = array();
            //判断组合数据是列表还是单个列
            if (isset($data['value']) && isset($data['group_id'])) {
                //单个列的值
                $datas[] = $data;

            } elseif (isset($data[0]['value']) && isset($data[0]['group_id'])) {
                $is_list = true;
                //列表值
                $datas = $data;
            } else {
                return self::setError('参数1传递的数组类型不正确');

            }
            if (!$ConfigGroup) {
                $ConfigGroup = self::getBaseGroupModel($dir, $app)->find($datas[0]['group_id']);
                if (!$ConfigGroup) return self::setError('找不到数据组');
            }
            $fields = $ConfigGroup['fields'];
            $configs = json_decode($fields, true);//json串传数组
            if ($configs === false) return self::setError('数据组解析失败,json格式异常');

            foreach ($datas as &$dt) {

                //解析数据
                $value = json_decode(htmlspecialchars_decode($dt['value']), true);
                unset($dt['value']);
                if (!$value) return self::setError('该数据解析失败,json格式异常');
                //得到每一个数据
                foreach ($configs as $config) {
                    if ($value) {
                        if (isset($value[$config['config_name']])) {
                            if ($config['type'] == 'upload') {

                                $r_textarea = base64_decode($value[$config['config_name']]['value']);
                                //var_dump($r_textarea);die;
                                $upload_info = json_decode(htmlspecialchars_decode(urldecode($r_textarea)), true);
                                $value[$config['config_name']]['value'] = $upload_info['src'] ?? null;
                            }
                            if ($config['type'] == 'r_textarea') {
                                $r_textarea = base64_decode($value[$config['config_name']]['value']);
                                //var_dump($r_textarea);die;
                                $value[$config['config_name']]['value'] = htmlspecialchars_decode(urldecode($r_textarea));
                            }
                            $dt[$config['config_name']] = $value[$config['config_name']]['value'];
                        } else {
                            $dt[$config['config_name']] = null;
                        }
                    } else {
                        $dt[$config['config_name']] = null;
                    }

                }

            }

            if ($is_list) {
                //列表
                $where = $datas;
            } else {
                //单个
                $where = $datas[0];
            }
            return $where;

        } catch (\Exception $e) {
            return self::setError($e->getMessage());
        }

    }


    public static function getDataList($groupName = '', $id = 0, $where = ['status' => 1], $page = null, $limit = null, $sort = 'sort desc,id desc')
    {
        if (!$groupName && !$id) return false;
        $memberId = null;
        $dir = null;
        if (is_array($groupName)) {
            $dir = $groupName[2] ?? null;
            $memberId = $groupName[1] ?? null;
            $groupName = $groupName[0];
        }
        $memberData = \buwang\util\Util::getLoginMemberId($memberId, $dir);//得到租户ID
        $member_id = $memberData['memberId']; //租户id
        $scopes = $memberData['scopes'];
        $dir = $memberData['dir'];
        if (!$member_id || $member_id < 0) $member_id = 0;
        $data = null;
        if ($dir) $data = self::getBaseQueryResult($id, $member_id, $groupName, $dir, $where, $sort, $page, $limit, true);//如果是应用环境优先查询应用组合数据
        if (!$data) $data = self::getBaseQueryResult($id, $member_id, $groupName, $dir, $where, $sort, $page, $limit);
        return $data;
    }

    public static function getBaseQueryResult($id, $member_id, $groupName, $dir, $where, $sort, $page, $limit, $app = false)
    {
        $groupData = self::getBaseDataModel($dir, $app);
        if ($member_id !== null) $groupData = $groupData->where('member_id', $member_id);
        $configGroup = self::getBaseGroupModel($dir, $app);
        if ($groupName) {
            if ($dir) {
                $configGroup = $configGroup->orderRaw("dir='{$dir}' desc");
            }
            $Group = $configGroup->where('id|config_name', '=', $groupName)->find();
            //TODO:2021/4/21 取组合数据的地方id改用
            if (!$Group) return [];
            if ($Group['dir']) $groupData = $groupData->where('dir', $Group['dir']);
            $groupData = $groupData->where('config_name', $Group['config_name'])->where('scopes', $Group['scopes']);
        }
        if ($id === false) return $groupData;
        $groupData = $groupData->where($where);
        //查单条
        if ($id && is_numeric($id)) {
            $data = $groupData->where('id', $id)->find();
            if (is_null($data) || $data instanceof stdClass || !$data) {
                return null;
            }
        } else {
            //查列表
            if ($sort) $groupData = $groupData->order($sort);
            if ($page && $limit) $groupData = $groupData->page($page, $limit);
            $data = $groupData->select()->toArray();
            if (!$data) return [];
        }
        $res = self::getValueData($data, null, $dir, $app);
        if ($res === false) return $res;
        return $data;
    }

    public static function getBaseDataModel($dir, $app)
    {
        if ($app && $dir) {
            $model = self::getAppGroupDataModel($dir); //从相关应用中取
            if (!$model) $model = new self;
        } else {
            $model = new self;
        }
        return $model;
    }

    public static function getBaseGroupModel($dir, $app)
    {
        if ($app && $dir) {
            $model = self::getAppGroupModel($dir); //从相关应用中取
            if (!$model) $model = new ConfigGroup;
        } else {
            $model = new ConfigGroup;
        }
        return $model;
    }

    /**获取对应应用的数据组model
     * @param $dir
     */
    public static function getAppGroupModel($dir)
    {
        $table_prefix = config('database.connections.mysql.prefix');//前缀
        $table_name = "{$table_prefix}{$dir}_config_group";
        //是否存在该表
        if (!Sql::existTable($table_name)) return false;
        $model_class = "\\app\\{$dir}\\model\\system\\ConfigGroup";
        //得到应用的model
        if (!class_exists($model_class)) return false;
        set_miniapp_database_prefix($dir);
        return new $model_class();
    }

    /**获取对应应用的组和数据项model
     * @param $dir
     */
    public static function getAppGroupDataModel($dir)
    {
        $table_prefix = config('database.connections.mysql.prefix');//前缀
        $table_name = "{$table_prefix}{$dir}_config_group_data";
        //是否存在该表
        if (!Sql::existTable($table_name)) return false;
        $model_class = "\\app\\{$dir}\\model\\system\\ConfigGroupData";
        //得到应用的model
        if (!class_exists($model_class)) return false;
        set_miniapp_database_prefix($dir);
        return new $model_class();
    }


}